<?php

namespace App\Services;

// 手动引入必要的类文件
require_once base_path('app/ThirdParty/ip2regiondata/ip2region/xdb/Util.php');
require_once base_path('app/ThirdParty/ip2regiondata/ip2region/xdb/IPv4.php');
require_once base_path('app/ThirdParty/ip2regiondata/ip2region/xdb/IPv6.php');
require_once base_path('app/ThirdParty/ip2regiondata/ip2region/xdb/Searcher.php');
require_once base_path('app/ThirdParty/ip2regiondata/ip2region/xdb/Ip2Region.php');
use ThirdParty\ip2regiondata\ip2region\xdb\Searcher;
use ThirdParty\ip2regiondata\ip2region\xdb\IPv4;
use ThirdParty\ip2regiondata\ip2region\xdb\IPv6;
use ThirdParty\ip2regiondata\ip2region\xdb\Util;
use ThirdParty\ip2regiondata\ip2region\xdb\Ip2Region;
use App\Services\BaseService;

class Ip2RegionService extends BaseService
{
    private $searcher;
    private $dbPath;
    private $cachePolicy;

    public function __construct($cachePolicy = 'vectorIndex')
    {
        $this->cachePolicy = $cachePolicy;
        $this->dbPath = $this->getDatabasePath();
        if (strpos($this->dbPath,'ip2region.db') == false) {
            $this->initSearcher();
        }
    }

    /**
     * 获取数据库文件路径
     */
    private function getDatabasePath()
    {
        // 优先使用 xdb 文件 storage_path
        $xdbPath = app_path('ThirdParty/ip2regiondata/ip2region/ip2region.db');

        if (file_exists($xdbPath)) {

            return $xdbPath;
        }

        // 使用你现有的 xdb 文件
        $existingXdb = app_path('ThirdParty/ip2regiondata/ip2region/ip2region_v4.xdb');
        if (file_exists($existingXdb)) {
            return $existingXdb;
        }

        // 如果都没有，尝试下载
        $this->downloadDatabase();
        return $xdbPath;
    }


    private function initSearcher2()
    {
        if (!file_exists($this->dbPath)) {
            $this->error("IP数据库文件不存在: {$this->dbPath}");
        }
    }

    /**
     * 初始化搜索器
     */
    private function initSearcher()
    {
        
        if (!file_exists($this->dbPath)) {
            $this->error("IP数据库文件不存在: {$this->dbPath}");
        }




        $handle = fopen($this->dbPath, 'r');
        if ($handle === false) {
            $this->error("无法打开数据库文件: {$this->dbPath}");
        }
        
        // 验证数据库文件
        $err = Util::verify($handle);
        if ($err != null) {
            fclose($handle);
            $this->error("数据库文件验证失败: {$err}");
        }

        // 加载头部信息
        $header = Util::loadHeader($handle);
        if ($header == null) {
            fclose($handle);
            $this->error("无法加载数据库头部信息");
        }

        // 获取版本
        try {
            $version = Util::versionFromHeader($header);
        } catch (Exception $e) {
            fclose($handle);
            $this->error("无法获取数据库版本: {$e->getMessage()}");
        }

        //fclose($handle);


        // 根据缓存策略创建搜索器
        switch ($this->cachePolicy) {
            case 'file':
                $this->searcher = Searcher::newWithFileOnly($version, $this->dbPath);
                break;
            case 'vectorIndex':
                $vIndex = Util::loadVectorIndex($handle);
                #dd($vIndex);
                if ($vIndex == null) {
                    $this->error("无法加载向量索引");
                }
                $this->searcher = Searcher::newWithVectorIndex($version, $this->dbPath, $vIndex);
                break;
            case 'content':
                $cBuff = Searcher::loadContent($handle);
                if ($cBuff == null) {
                    $this->error("无法加载数据库内容");
                }
                $this->searcher = Searcher::newWithBuffer($version, $cBuff);
                break;
            default:
                $this->error("不支持的缓存策略: {$this->cachePolicy}");
        }
    }

    /**
     * IP地址查询
     */
    public function search($ip)
    {
        if($ip=='127.0.0.1'){
            $region="本地|0|本地|本地|本地";
            return [
                'ip' => $ip,
                'region' => $region,
                'parsed' => $this->parseRegion($region),
                'io_count' => 0,
                'took_ms' => time(),
                'cache_policy' => 0
            ];


        }
        $startTime = microtime(true);
        if (strpos($this->dbPath,'ip2region.db') !== false && $ip !='127.0.0.1') {
            if (!$this->isValidIp($ip)) {
                $this->error("无效的IP地址: {$ip}");
            }
            $ip2region = new Ip2Region();

            #$ip = '61.140.232.170';

            $region = $ip2region->memorySearch($ip);
            $region=$region['region'];
            $cost = round((microtime(true) - $startTime) * 1000, 5);
            return [
                'ip' => $ip,
                'region' => $region,
                'parsed' => $this->parseRegion($region),
                'io_count' => 0,
                'took_ms' => $cost,
                'cache_policy' => 0
            ];

        }else{
            if (!$this->isValidIp($ip)) {
                $this->error("无效的IP地址: {$ip}");
            }
            $region = $this->searcher->search($ip);
            $cost = round((microtime(true) - $startTime) * 1000, 5);

            return [
                'ip' => $ip,
                'region' => $region,
                'parsed' => $this->parseRegion($region),
                'io_count' => $this->searcher->getIOCount(),
                'took_ms' => $cost,
                'cache_policy' => $this->cachePolicy
            ];
        }
        
           
        
    }

    /**
     * 批量查询IP地址
     */
    public function batchSearch(array $ips)
    {
        $results = [];
        
        foreach ($ips as $ip) {
            if ($this->isValidIp($ip)) {
                try {
                    $results[$ip] = $this->search($ip);
                } catch (Exception $e) {
                    $results[$ip] = ['error' => $e->getMessage()];
                }
            } else {
                $results[$ip] = ['error' => '无效的IP地址'];
            }
        }
        
        return $results;
    }

    /**
     * 解析地区信息
     */
    private function parseRegion($region)
    {
        if (empty($region)) {
            return [
                'country' => '',
                'region' => '',
                'province' => '',
                'city' => '',
                'isp' => ''
            ];
        }

        //dd($region);
        $parts = explode('|', $region);

        //dd($parts);
        $result=[
            'country' => $parts[0] !== '0' ? $parts[0] : '',
            'region' => $parts[1] !== '0' ? $parts[1] : $parts[2],
            'province' => $parts[2] !== '0' ? $parts[2] : '',
            'city' => $parts[3] !== '0' ? $parts[3] : '',
            'isp' => $parts[4] !== '0' ? $parts[4] : '',
        ];
        
        return $result;
    }

    /**
     * 验证IP地址格式
     */
    private function isValidIp($ip)
    {
         
        return filter_var($ip, FILTER_VALIDATE_IP) !== false;
    }

    /**
     * 获取客户端IP地址
     */
    public function getClientIp()
    {
        
        $ip = '';
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } elseif (!empty($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        
        // 处理多个IP的情况（如经过代理）
        if (strpos($ip, ',') !== false) {
            $ips = explode(',', $ip);
            $ip = trim($ips[0]);
        }



        return $ip;

    }

    /**
     * 查询客户端IP信息
     */
    public function getClientInfo()
    {
        $clientIp = $this->getClientIp();
        
        return $clientIp;
    }

    /**
     * 下载数据库文件
     */
    private function downloadDatabase()
    {
        $dbUrl = 'https://github.com/lionsoul2014/ip2region/tree/master/data/ip2region_v4.xdb';
        $savePath = storage_path('app/ip2region_v4.xdb');

        try {
            $content = file_get_contents($dbUrl);
            if ($content) {
                file_put_contents($savePath, $content);
            }
        } catch (Exception $e) {
            $this->error("下载数据库文件失败: {$e->getMessage()}");
        }
    }

    /**
     * 销毁时关闭搜索器
     */
    public function __destruct()
    {
        if ($this->searcher) {
            $this->searcher->close();
        }
    }
}
